package com.tanjor.sys.service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import com.tanjor.sys.entity.SysMenu;
import com.tanjor.sys.dubbo.dto.SysMenuDTO;
import com.tanjor.sys.dubbo.dto.SysRoleMenuDTO;
import com.tanjor.sys.mapper.SysMenuMapper;
import com.tanjor.sys.service.interfaces.ISysMenuService;
import com.tanjor.sys.service.interfaces.ISysRoleMenuService;
import com.tanjor.sys.util.SysConstantUtil;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.tanjor.common.datatable.ColumnFilter;
import com.tanjor.common.datatable.PageReq;
import com.tanjor.common.datatable.PageResp;
import com.tanjor.common.exception.BusinessException;
import com.tanjor.common.redis.interfaces.RedisService;
import com.tanjor.common.util.ObjectUtil;

import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.toolkit.IdWorker;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Liuwy
 * @since 2017-04-02
 */
@Service("SysMenuServiceImpl")
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {
	
	@Resource(name="SysRoleMenuServiceImpl")
	private ISysRoleMenuService sysRoleMenuService;
	
	@Resource
	private RedisService redisService;
	
	/**
	 * 根据父菜单编号查询菜单
	 * @param pid
	 * @return List<SysMenu>
	 */
	private List<SysMenu> findByPid(String pid){
		EntityWrapper<SysMenu> wrapper = new EntityWrapper<SysMenu>();
		wrapper.and("pId={0}", pid);
		wrapper.and("active={0}", "1");
		wrapper.orderBy("seq", true);
		List<SysMenu> list = this.baseMapper.selectList(wrapper);
		return list;
	}
	
	/**
	 * 查询所有菜单
	 * @return List<SysMenu> 
	 */
	private List<SysMenu> findAll(){
		EntityWrapper<SysMenu> wrapper = new EntityWrapper<SysMenu>();
		wrapper.orderBy("seq", true);
		List<SysMenu> list = this.baseMapper.selectList(wrapper);
		return list;
	}
	
	/**
	 * 查询所有菜单
	 * @return List<SysMenu> 
	 */
	@Override
	public List<SysMenuDTO> findAllMenus(){
		return this.copyList(this.findAll());
	}
	
	/**
	 * 判断菜单是否分配权限
	 * @param menuid
	 * @param roleMenus
	 * @return boolean
	 */
	private boolean hasPermission(String menuid,List<SysRoleMenuDTO> roleMenus){
		boolean result = false;
		for(SysRoleMenuDTO rolemenu:roleMenus){
			if(rolemenu.getMenuId().equals(menuid)){
				result = true;
				break;
			}
		}
		return result;
	}
	
	/**
	 * 获取全部Map形式存储的菜单缓存
	 * @return Map<String,SysMenu>
	 */
	private Map<String,SysMenu> findAllMenusCache(){
		Map<String,SysMenu> menus = redisService.getCacheValue(SysConstantUtil.MENU.ALL_MAP_MENUS, HashMap.class);
		if(menus==null){
			menus = new HashMap<String,SysMenu>();
			List<SysMenu> sysMenus = findAll();
			for(SysMenu sysMenu:sysMenus){
				menus.put(sysMenu.getId(), sysMenu);
			}
			redisService.setCacheValue(SysConstantUtil.MENU.ALL_MAP_MENUS, menus);
		}
		return menus;
	}
	
	/**
	 * 根据菜单编号更新菜单缓存
	 * @param menuId
	 */
	private void reflashAllMenusCache(Serializable menuId,String method){
		if(method.equals("update")||method.equals("add")){
			SysMenu sysMenu = this.baseMapper.selectById(menuId);
			Map<String,SysMenu> menus = redisService.getCacheValue(SysConstantUtil.MENU.ALL_MAP_MENUS, HashMap.class);
			menus.put(menuId.toString(), sysMenu);
			redisService.setCacheValue(SysConstantUtil.MENU.ALL_MAP_MENUS, menus);
		}else if(method.equals("del")){
			Map<String,SysMenu> menus = redisService.getCacheValue(SysConstantUtil.MENU.ALL_MAP_MENUS, HashMap.class);
			menus.put(menuId.toString(), null);
			redisService.setCacheValue(SysConstantUtil.MENU.ALL_MAP_MENUS, menus);
		}
	}
	
	/**
	 *  List<SysMenu> to List<SysMenuDTO>
	 */
	private  List<SysMenuDTO> copyList(List<SysMenu> list){
		List<SysMenuDTO> entityDTOs = new ArrayList<SysMenuDTO>();
		Map<String,SysMenu> menus = this.findAllMenusCache();
		if(list!=null){
			for(SysMenu entity:list){
				SysMenuDTO entityDTO = new SysMenuDTO();
				ObjectUtil.copy(entity,entityDTO);				
				SysMenu pMenu = menus.get(entityDTO.getPId());
				if(pMenu!=null){
					entityDTO.setpName(pMenu.getName());
				}
				entityDTOs.add(entityDTO);
			}
		}
		return entityDTOs;
	}
	
	/**
	 * 分页入参构造器
	 * @param pageReq
	 * @return
	 */
	private EntityWrapper<SysMenu> createWrapper(PageReq pageReq){
		EntityWrapper<SysMenu> wrapper = new EntityWrapper<SysMenu>();
		if(pageReq.getColumnFilters()!=null){
			for(ColumnFilter columnFilter:pageReq.getColumnFilters()){
				//按需求构造入参
				switch (columnFilter.getName()){
					case "name" :{
						wrapper.and("name like {0}", columnFilter.getValue());
						break;
					}
					case "pId" :{
						wrapper.and("pId={0}", columnFilter.getValue());
						break;
					}
				}
				
			}
		}	
		return wrapper;
	}
	
	@Override
	public PageResp findPage(PageReq pageReq) {
		// TODO Auto-generated method stub
		PageResp page = new PageResp();
		pageReq.setOrderBy("pId");
		pageReq.setIsAsc(true);
		//请求标志位
		page.setDraw(pageReq.getDraw());
		//构造条件
		EntityWrapper<SysMenu> wrapper = createWrapper(pageReq);
		
		Integer totalRows = this.baseMapper.selectCount(wrapper);
		
		if(StringUtils.isNotBlank(pageReq.getOrderBy())){
			wrapper.orderBy(pageReq.getOrderBy(), pageReq.getIsAsc());			
		}
		wrapper.orderBy("seq",true);
		//查询
		List<SysMenuDTO> list = findPage(wrapper, pageReq.getStart(), pageReq.getLength());	
		//构造返回
		page.setData(list);
		page.setRecordsFiltered(totalRows);
		page.setRecordsTotal(totalRows);
		return page;
	}
	
	@Override
	public List<SysMenuDTO> findPage(Wrapper<SysMenu> wrapper,int start,int limit) {
		// TODO Auto-generated method stub
		List<SysMenu> list = baseMapper.selectPage(new RowBounds(start, limit), wrapper);
		return this.copyList(list);
	}
	
	@Override
	public Map<String,Object> insert(SysMenuDTO entityDTO) throws BusinessException{
		// TODO Auto-generated method stub	
		Map<String,Object> map = new HashMap<String,Object>();
		entityDTO.setId(""+IdWorker.getId());
		SysMenu entity = new SysMenu();
		ObjectUtil.copy(entityDTO,entity);
		this.insert(entity);
		//更新缓存
		this.reflashAllMenusCache(entity.getId(),"add");
		map.put("result", true);
		return map;
	}
	
	@Override
	public Map<String,Object> update(SysMenuDTO entityDTO) throws BusinessException{
		Map<String,Object> map = new HashMap<String,Object>();
		// TODO Auto-generated method stub
		SysMenu entity = new SysMenu();
		ObjectUtil.copy(entityDTO,entity);
		this.updateById(entity);
		//更新缓存
		this.reflashAllMenusCache(entity.getId(),"update");
		map.put("result", true);
		return map;
	}
	
	@Override
	public SysMenuDTO findById(Serializable id){
		// TODO Auto-generated method stub
		SysMenuDTO entityDTO = new SysMenuDTO();
		SysMenu entity = this.selectById(id);
		ObjectUtil.copy(entity,entityDTO);
		return entityDTO;
	}

	@Override
	public Map<String, Object> delById(Serializable id) throws BusinessException {
		// TODO Auto-generated method stub
		Map<String,Object> map = new HashMap<String,Object>();
		EntityWrapper<SysMenu> wrapper = new EntityWrapper<SysMenu>();
		wrapper.and("pId={0}", id);
		int num = this.selectCount(wrapper);
		if(num<1){
			this.deleteById(id);
			//更新缓存
			this.reflashAllMenusCache(id,"del");
			map.put("result", true);
		}else{
			map.put("result", false);
			map.put("msg", "该菜单含有子菜单，无法删除！");
		}
		return map;
	}
	
	@Override
	public List<Map<String,Object>> findTreeByRole(String roleCode) {
		// TODO Auto-generated method stub
		List<Map<String,Object>> menus = new ArrayList<Map<String,Object>>();	
		List<SysRoleMenuDTO> roleMenus = sysRoleMenuService.findByRoleCode(roleCode);		
		List<SysMenu> topMenus = this.findAll();
		for(SysMenu sysmenu:topMenus){
			Map<String,Object> menu = new HashMap<String,Object>();
			menu.put("id", sysmenu.getId());
			menu.put("name", sysmenu.getName());
			menu.put("pId",sysmenu.getPId());	
			menu.put("checked", hasPermission(sysmenu.getId(),roleMenus));
			menus.add(menu);
		}
		
		return menus;
	}
	
	@Override
	public List<Map<String,Object>> findByRole(String roleCode) {
		// TODO Auto-generated method stub
		//获取顶层节点
		List<Map<String,Object>> menus = new ArrayList<Map<String,Object>>();
		List<SysRoleMenuDTO> roleMenus = sysRoleMenuService.findByRoleCode(roleCode);	
		Map<String,SysMenu> menuMaps = this.findAllMenusCache();
		for(SysRoleMenuDTO sysRolemenu:roleMenus){
			SysMenu sysmenu = menuMaps.get(sysRolemenu.getMenuId());
			if(!sysmenu.getPId().equals("0")){
				continue;
			}
			Map<String,Object> menu = new HashMap<String,Object>();
			menu.put("id", sysmenu.getId());
			menu.put("name", sysmenu.getName());
			menu.put("icons", sysmenu.getIcons());
			menu.put("pid", sysmenu.getPId());
			//获取子节点下
			List<Map<String,Object>> childmenus = new ArrayList<Map<String,Object>>();
			List<SysMenu> childMenus = this.findByPid(sysmenu.getId());
			for(SysMenu childMenu:childMenus){
				if(hasPermission(childMenu.getId(),roleMenus)){
					Map<String,Object> child = new HashMap<String,Object>();
					child.put("id", childMenu.getId());
					child.put("name", childMenu.getName());
					child.put("icons", childMenu.getIcons());
					child.put("url", childMenu.getUrl());
					child.put("pid", childMenu.getPId());
					childmenus.add(child);	
				}
			}
			menu.put("child", childmenus);
			menus.add(menu);
		}
		return menus;
	}

	@Override
	public List<Map<String, Object>> findTopTree() {
		// TODO Auto-generated method stub
		//获取顶层节点
		List<Map<String,Object>> menus = new ArrayList<Map<String,Object>>();
		List<SysMenu> topMenus = this.findByPid("0");
		for(SysMenu sysmenu:topMenus){
			Map<String,Object> menu = new HashMap<String,Object>();
			menu.put("id", sysmenu.getId());
			menu.put("name", sysmenu.getName());
			menu.put("icons", sysmenu.getIcons());
			menu.put("pid", sysmenu.getPId());				
			menus.add(menu);
		}
		return menus;
	}

}
